﻿/*
 * DATAFLOWCORE
 *
 * 
Copyright 2013 - WIDE IO LTD
Copyright 2012 - Mindstorm Multitouch Limited

Author - Bertrand Nouvel

DataFlowCore is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

DataFlowCore is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser Public License for more details.
*/

using MongoDB.Bson;
using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;
using System.Net;
using System.Net.Sockets;
using System.Linq;



namespace DFlowCore
{

    public partial class Engine : MarshalByRefObject
    {
        // AVAILABLE ELEMENTS


        /// <summary>
        /// List of paths to DLLs that may be used as dependencies of plugins
        /// </summary>
        static protected System.Collections.Generic.Dictionary<string,string> known_dlls = new Dictionary<string,string>();


        /// <summary>
        /// List of paths to assemblies that may be loaded as plugins
        /// </summary>
        static protected System.Collections.Generic.List<string> known_plugins = new List<string>();


        /// <summary>
        /// Plugins to load at startup
        /// </summary>
        static protected System.Collections.Generic.List<string> assemblies_to_load = new List<string>();                                                // assemblies to load

        /// <summary>
        /// Already loaded pluging
        /// </summary>
        static protected System.Collections.Generic.List<System.Reflection.Assembly> loaded_assemblies = new List<System.Reflection.Assembly>();         // loaded assemblies

        /// <summary>
        /// Date & time of the module that is reloaded | may be used for reloading the domain on the fly
        /// </summary>
        static protected System.Collections.Generic.Dictionary<string, System.DateTime> loaded_assemblies_time = new Dictionary<string, System.DateTime>(); // <- associate with reload

        /// <summary>
        /// List of commands provided by the engine [ Used for server Implementations ]
        /// </summary>
        static protected System.Collections.Generic.Dictionary<string, ServerCommand> vogon_commands = new System.Collections.Generic.Dictionary<string, ServerCommand>();


        /// <summary>
        /// Exhaustive list of all registered nodes
        /// Type may be replace by replace by delegate / factory ?
        /// </summary>
        static protected System.Collections.Generic.Dictionary<string, System.Type> nodetypes
                = new System.Collections.Generic.Dictionary<string, System.Type>();
        static protected System.Collections.Generic.Dictionary<string, System.Type> moduletypes
                = new System.Collections.Generic.Dictionary<string, System.Type>();


        // DATA QUERIES
        public string plugin_lookup_path = ".{4}";
        public string dll_lookup_path    = ".{4}";


        protected AppDomain appdomain;

        // DATAFLOWS
        protected System.Collections.Generic.List<DFlow.Dataflow> masterDataflows = new List<DFlow.Dataflow>();
        protected DFlow.Dataflow currentDataflow = null;


        // Net Debug / Error Settings (Required Here For Commands)
        public static bool forwardExceptions = true;
        public static bool withNetDebug = false;








        // INTERNAL STATE
        protected bool continueMainLoop = true;
        protected System.Collections.Generic.Dictionary<string, object> variables;

        protected Engine running_engine = null;

        protected static Engine _Current;
        public static Engine Current {
            get { return _Current; }
        }

        public Engine()
        {
            if (variables == null)
            {
                variables = new Dictionary<string, object>();
            }

            appdomain = AppDomain.CurrentDomain;
            running_engine = this; // by default we assume that we don't user anysubdoamin
            _Current = this;
        }


        public void SetVariable(string varname, string value)
        {
            variables[varname] = value;
        }



        #region SERVER_COMMANDS

        /// <summary>
        /// A command for the server is method that takes as input a bsondocument
        /// and returns a bson document
        /// </summary>
        [AttributeUsage(AttributeTargets.Method)]
        public class ServerCommand : System.Attribute
        {
            public BsonDocument Execute(BsonDocument d)
            {
                return (BsonDocument)ExecuteF(d);
            }
            public delegate object ExecuteD(object d);
            public ExecuteD ExecuteF;

            public string[] aliases;
            public ServerCommand(params string[] _aliases)
            {
                aliases = _aliases;
            }
        }


        // Well actually in most of the case the marshalling/unmarshalling can be done
        // automatically
        [AttributeUsage(AttributeTargets.Method)]
        public class AutoServerCommand : ServerCommand
        {
            public object instance;
            public System.Reflection.MethodInfo method;
            public object AutoExecute(object _q)
            {
                BsonDocument q = (BsonDocument)_q;
                BsonDocument res = new BsonDocument();
                System.Reflection.ParameterInfo[] pi = method.GetParameters();
                object[] cparams = new object[pi.Length];
                for (int i = 0; i < pi.Length; i++)
                {
                    if ((q != null) && (q.Contains(pi[i].Name)))
                    {
                        try
                        {
                            cparams[i] = DFlowCore.BsonUtils.BsonDecode(q[pi[i].Name], pi[i].ParameterType);
                        }
                        catch (System.Exception se)
                        {
                            DFlowCore.Log.Warning(se.ToString());

                        }
                    }
                    else
                    {
                        if (pi[i].IsOptional)
                        {
                            cparams[i] = pi[i].DefaultValue;

                        }
                        else
                        {
                            DFlowCore.Log.Warning("Missing parameter " + pi[i].Name);
                            res["error"] = "Missing parameter " + pi[i].Name;
                            return res;
                        }
                    }
                }

                try
                {
                    DFlowCore.Log.Debug("q " + method.Name + " " + ((q != null) ? q.ToString() : "NULL"));
                    object tres = method.Invoke(instance, cparams);
                    res["res"] = DFlowCore.BsonUtils.BsonEncode(tres, tres.GetType());

                    if (withNetDebug)
                    {
                        DFlowCore.Log.Debug("->" + res["res"].ToString() + "/" + tres.GetType().Name);
                    }
                }
                catch (System.Reflection.TargetInvocationException se)
                {
                    DFlowCore.Log.Error(se.InnerException.ToString());
                    res["error"] = se.ToString();
                }

                return res;
            }

            public AutoServerCommand(params string[] _aliases)
                : base(_aliases)
            {
                ExecuteF = AutoExecute;
            }

        }

     #endregion

        #region UTILITY_FUNCTIONS
        public BsonDocument TranslateMetadata(System.Reflection.FieldInfo fi)
        {
            BsonDocument bd = new BsonDocument();
            foreach (object a in fi.GetCustomAttributes(typeof(DFlow.Attribute), true))
            {
                DFlow.Attribute at = (a as DFlow.Attribute);
                at.UpdateBson(bd);
            }
            return bd;
        }


        public string SubstituteVariables(string s)
        {
            Regex reg = new Regex(@"(\$\()([^}]+)(\))", RegexOptions.IgnoreCase);
            MatchCollection mc = reg.Matches(s);
            int startIndex = 0;
            string sb = "";
            foreach (Match m in mc)
            {
                Group g = m.Groups[2]; //it's second in the match between { and }
                int length = g.Index - startIndex - 2;
                sb+=(s.Substring(startIndex, length));
                sb+=(variables[s.Substring(g.Index, g.Length)] as string);
                startIndex = g.Index + g.Length + 1;
            }
            sb+=(s.Substring(startIndex,s.Length-startIndex));
            return sb;
        }

        public static bool IsManagedAssembly(string fileName)
        {
            uint peHeader;
            uint peHeaderSignature;
            ushort machine;
            ushort sections;
            uint timestamp;
            uint pSymbolTable;
            uint noOfSymbol;
            ushort optionalHeaderSize;
            ushort characteristics;
            ushort dataDictionaryStart;
            uint[] dataDictionaryRVA = new uint[16];
            uint[] dataDictionarySize = new uint[16];

            Stream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read,FileShare.Read, 256,false);
            BinaryReader reader = new BinaryReader(fs);

            //PE Header starts @ 0x3C (60). Its a 4 byte header.
            fs.Position = 0x3C;
            peHeader = reader.ReadUInt32();

            //Moving to PE Header start location...
            fs.Position = peHeader;
            peHeaderSignature = reader.ReadUInt32();

            //We can also show all these value, but we will be       
            //limiting to the CLI header test.
            machine = reader.ReadUInt16();
            sections = reader.ReadUInt16();
            timestamp = reader.ReadUInt32();
            pSymbolTable = reader.ReadUInt32();
            noOfSymbol = reader.ReadUInt32();
            optionalHeaderSize = reader.ReadUInt16();
            characteristics = reader.ReadUInt16();

            // Now we are at the end of the PE Header and from here, the PE Optional Headers starts... To go directly to the datadictionary, we'll increase the stream’s current position to with 96 (0x60). 96 because, 28 for Standard fields 68 for NT-specific fields From here DataDictionary starts...and its of total 128 bytes. DataDictionay has 16 directories in total, doing simple maths 128/16 = 8. So each directory is of 8 bytes. In this 8 bytes, 4 bytes is of RVA and 4 bytes of Size. btw, the 15th directory consist of CLR header! if its 0, its not a CLR file :)
            dataDictionaryStart = Convert.ToUInt16(Convert.ToUInt16(fs.Position) + 0x60);
            fs.Position = dataDictionaryStart;
            for (int i = 0; i < 15; i++)
            {
                dataDictionaryRVA[i] = reader.ReadUInt32();
                dataDictionarySize[i] = reader.ReadUInt32();
            }
            fs.Close();

            if (dataDictionaryRVA[14] == 0) return false;
            else return true;
        }

        public static ushort GetPEArchitecture(string pFilePath)
        {

            ushort architecture = 0;
            try
            {
                using (System.IO.FileStream fStream = new System.IO.FileStream(pFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
                {
                    using (System.IO.BinaryReader bReader = new System.IO.BinaryReader(fStream))
                    {
                        if (bReader.ReadUInt16() == 23117) //check the MZ signature
                        {
                            fStream.Seek(0x3A, System.IO.SeekOrigin.Current); //seek to e_lfanew.
                            fStream.Seek(bReader.ReadUInt32(), System.IO.SeekOrigin.Begin); //seek to the start of the NT header.
                            if (bReader.ReadUInt32() == 17744) //check the PE\0\0 signature.
                            {
                                fStream.Seek(20, System.IO.SeekOrigin.Current); //seek past the file header,
                                architecture = bReader.ReadUInt16(); //read the magic number of the optional header.
                            }
                        }
                    }
                }
            }
            catch (Exception)
            { /* TODO: Any exception handling you want to do, personally I just take 0 as a sign of failure *
                             * 
                             */
                return 0;
            }


            //if architecture returns 0, there has been an error.
            return architecture;
        }


        public string[] PluginNameTags = {
          "dflow",
          "crusoe",
          "mindstorm",
          "vogon"
        };

        public bool  CheckValidPluginName(string s) {
            s=s.ToLower();
            foreach(string e in PluginNameTags ) {
                if (s.Contains(e)) {
                    return true;
                }
            }

            return false;
        }


        public bool CheckValidPluginAssembly(string s)
        {
            //System.Reflection.Module m=new System.Reflection.Module()
            //System.Configuration.ConfigurationSettings.AppSettings.Keys["truc"]
            //int r = GetPEArchitecture(s);
            //if (r == 0) 
            //    return false;


            // THIS IS THE FASTEST WAY TO FILTER VALID / INVALID PLUGINS IN CURRENT VERSION
            // WHERE WE MAY STILL FACE A LOT OF ASSEMBLIES..
            if (!CheckValidPluginName(System.IO.Path.GetFileName(s)))
            {
                return false;
            }

            
            if (!IsManagedAssembly(s))
            {
#if WITH_CHECK_VALID_ASSEMBLY_DEBUG
                DFlowCore.Log.Debug("NO  :"+s, 0);
#endif
                return false;
            }

#if WITH_CHECK_VALID_ASSEMBLY_DEBUG
            DFlowCore.Log.Debug("YES :" + s, 0);
#endif
            //DFlowCore.Log.Debug((r & 0x30).ToString() + ":" + System.IO.Path.GetFileName(s), 0);
            try
            {
                System.Reflection.AssemblyName testAssembly =
                    System.Reflection.AssemblyName.GetAssemblyName(s);

                return true;
            }
            catch { }

            return false;
        }


        IEnumerable<DFlow.Pair<string, int>> ParsePluginLookupPath(string cp)
        {
            foreach (string p in cp.Split(new char[] { ';' }))
            {
                string xp = p;
                int pl = 0;
                if (p.EndsWith("}"))
                {
                    int cpl = p.IndexOf('{');
                    if (cpl != -1)
                    {
                        if (!int.TryParse(p.Substring(cpl + 1, p.Length - 2 - cpl), out pl))
                        {
                            pl = 0;
                        }
                        else
                        {
                            xp = p.Substring(0, cpl);
                        }
                    }
                    if ((pl < 0) || (pl > 8)) { pl = 0; }
                }

                yield return new DFlow.Pair<string, int>(xp, pl);
            }
        }

        #endregion



        public bool ShouldReloadAssemblies()
        {
            return false;
        }

        public bool ShouldContinue()
        {
            return true;
        }

        protected void RunDataflow()
        {
            foreach (DFlow.Dataflow pp in masterDataflows)
            {
                if (pp.runmode == DFlow.Dataflow.RunMode.Automatic)
                {
                    pp.Process();
                }
            }
        }




        public virtual void OneStepIter()
        {
            DFlowCore.Time.Tick();
            RunDataflow();

            DFlowCore.Time.Tick(false);

            foreach (DFlow.Module m in DFlow.Module.Instances)
            {
                m.OnProcess();
            }

        }




        void MainLoop()
        {
            while (continueMainLoop)
            {
                running_engine.OneStepIter();
            }

        }


        protected void DebugEnumerateKnownDlls()
        {
            DFlowCore.Log.Debug("[DLLs dump]", 0);
            foreach (string s in known_dlls.Values)
            {
                DFlowCore.Log.Debug(s, 0);
            }
            DFlowCore.Log.Debug("[/DLLs dump]", 0);
        }


        /// <summary>
        /// Function To Be Called To Initialize The Engine 
        /// </summary>
        public void DoStartRunningEngine(bool createdataflow=true)
        {
            running_engine.DoLookForNewAssemblies();
            running_engine.DoLookForDLLs();
            //running_engine.DebugEnumerateKnownDlls();

            // --------------------------------------------------------------------------
            // try load UI & splash screen if necessary

            // --------------------------------------------------------------------------
            // Load all other required plugins
            DFlowCore.Time.Tick();            

            running_engine.DoLookForPlugins();
            DFlowCore.Time.Tick();
            DFlowCore.Log.Info("Time spent looking for plugin : "+DFlowCore.Time.deltat.ToString());
            running_engine.DoLoadAssemblies();
            DFlowCore.Time.Tick();
            DFlowCore.Log.Info("Time spent loading assemblies : " + DFlowCore.Time.deltat.ToString());
            running_engine.DoRegisterCommands();
            running_engine.DoSetupNetwork();
            // --------------------------------------------------------------------------
            // Get ready to start
            if (createdataflow)
            {
                running_engine.EngineSetNewDataflow();
            }

            DFlowCore.Time.Tick();
            DFlowCore.Log.Info("Time spent finalizing engine setup : " + DFlowCore.Time.deltat.ToString());

            running_engine.EngineInitialized();
            //running_engine.EngineStartSeparateThread();
        }


        public delegate void OnEngineInitializedD();
        public event OnEngineInitializedD OnEngineInitialized;
        public virtual void EngineInitialized()
        {
            if (OnEngineInitialized!=null) {
                OnEngineInitialized();
            }
        }

        protected void DoLookForNewAssemblies()
        {
            foreach (System.Reflection.Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
            {
                RegisterAssembly(asm);
            }

            AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad;
        }





        /// <summary>
        /// Looks for the latest builds dll matching a filter
        /// </summary>
        protected void _DoLookForDLLs(string dll_lookup_path, 
                                     Func<string,bool> IsValidDLLDelegate,
                                     Func<string,bool> OnAddNewDelegate
            )
        {
            Dictionary<string, DFlow.Pair<string, System.DateTime>> potential_plugins = new Dictionary<string, DFlow.Pair<string, DateTime>>();

            Func<string, string> p = System.IO.Path.GetDirectoryName;


            foreach (DFlow.Pair<string, int> plp in ParsePluginLookupPath(dll_lookup_path))
            {
                string P = plp.first;
                if ((P == ".") || (P == null))
                {
                    P = System.IO.Directory.GetCurrentDirectory();
                }

                for (int i = 0; i < plp.second; i++)
                {
                    P = p(P);

                    if (P == null)
                    {
                        P = System.IO.Directory.GetCurrentDirectory();
                    }
                }


                if (P != null)
                {
                    try
                    {
                        foreach (
                            string cp in
                              System.IO.Directory.GetFiles(P, "*.dll", SearchOption.AllDirectories).Where(x => IsValidDLLDelegate(x))

                            )
                        {
                            string f = System.IO.Path.GetFileName(cp).ToLower();
                            if (potential_plugins.ContainsKey(f))
                            {
                                System.DateTime dt = System.IO.File.GetLastWriteTimeUtc(cp);
                                if (potential_plugins[f].second < dt)
                                {
                                    potential_plugins[f] = new DFlow.Pair<string, DateTime>(cp, dt);
                                }
                            }
                            else
                            {
                                potential_plugins.Add(f,
                                    new DFlow.Pair<string, DateTime>(cp,
                                        System.IO.File.GetLastWriteTimeUtc(cp)
                                        )
                                );
                            }
                        }
                    }
                    catch (System.Exception e)
                    {
                        DFlowCore.Log.Error(e.ToString());
                    }
                }
                foreach (string s in potential_plugins.Values.Select(x => x.first))
                {
                    OnAddNewDelegate(s);
                }                
            }
        }



        /// <summary>
        /// Looks for the latest build assemblies within our search path
        /// </summary>
        protected void DoLookForPlugins()
        {
            
            known_plugins.Clear();
            _DoLookForDLLs(plugin_lookup_path, CheckValidPluginAssembly, x => { 
                known_plugins.Add(x); 
                return true; 
              }
            );
        }


        /// <summary>
        /// Looks for the latest build assemblies within our search path
        /// </summary>
        protected void DoLookForDLLs()
        {

            known_dlls.Clear();
            _DoLookForDLLs(dll_lookup_path,
                            x => true,
                            x => { 
                                known_dlls.Add(System.IO.Path.GetFileName(x),x); return true; 
                            }
                          );
        }


        protected virtual void DoSetupNetwork()
        { }




        protected void DoRegisterCommands()
        {
            Type t = typeof(Engine);
            vogon_commands.Clear();

            foreach (System.Reflection.MethodInfo mi in t.GetMethods())
            {
                foreach (object a in mi.GetCustomAttributes(typeof(ServerCommand), false))
                {
                    ServerCommand sc = (ServerCommand)a;
                    if (sc.ExecuteF == null)
                    {
                        sc.ExecuteF = ((object o) => mi.Invoke(this, new object[] { o }));
                    }
                    else
                    {
                        AutoServerCommand asc = (sc as AutoServerCommand);
                        if (asc != null)
                        {
                            asc.method = mi;
                            asc.instance = this;
                        }
                    }
                    vogon_commands.Add(mi.Name, sc);
                    foreach (string sal in sc.aliases)
                    {
                        vogon_commands.Add(sal, sc);
                    }
                }
            }
        }




        /// <summary>
        /// Launches a new dataflow
        /// </summary>
        protected void EngineSetNewDataflow()
        {
            masterDataflows.Add(currentDataflow = new DFlow.Dataflow());
        }




        public BsonDocument TranslateMetadata(System.Type t)
        {
            BsonDocument bd = new BsonDocument();
            foreach (object a in t.GetCustomAttributes(typeof(DFlow.Attribute), true))
            {
                DFlow.Attribute at = (a as DFlow.Attribute);
                at.UpdateBson(bd);
            }
            return bd;
        }



        #region ASSEMBLY_LOADING


        public static string MakeNodeName(Type tp) {
                //return ((tp.Assembly.GetCustomAttributes(typeof(System.Reflection.AssemblyTitleAttribute), false))[0] as System.Reflection.AssemblyTitleAttribute).Title + "::" + tp.Name;
            return tp.FullName+"@"+tp.Assembly.ManifestModule.Name;
            //return ((tp.Assembly.GetCustomAttributes(typeof(System.Reflection.AssemblyTitleAttribute), false))[0] as System.Reflection.AssemblyTitleAttribute).+ "::" + tp.Name;
        }

        static public void RegisterAssembly(System.Reflection.Assembly asm)
        {
            //            System.Reflection.Assembly asm = args.LoadedAssembly;
            try
            {
                foreach (System.Type tp in asm.GetExportedTypes())
                {
                    if (tp != null)
                    {
                        try
                        {
                            if (tp.IsSubclassOf(typeof(DFlow.Node))
                                && (!tp.IsGenericTypeDefinition)
                                && (!tp.IsAbstract)
                                && (!tp.IsSubclassOf(typeof(DFlow.__DataShowingControl)))
                                )
                            {
                                string nn=MakeNodeName(tp);
                                if (!nodetypes.ContainsKey(nn))
                                {
                                    DFlowCore.Log.Debug("Registering "+nn,0);
                                    nodetypes.Add(nn, tp);
                                }
                            }
                        }
                        catch (System.Exception se)
                        {
                            DFlowCore.Log.Error(se.ToString());
                        }
                    }

                }
            }
            catch (System.Exception se)
            {
                DFlowCore.Log.Error(se.ToString());
            }
        }




        /// <summary>
        /// Event handler for AssemblyLoad Event
        /// </summary>
        void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
        {
            RegisterAssembly(args.LoadedAssembly);
        }

    
        // Ensure that all requested assemblies are loaded
        protected void DoLoadAssemblies()
        {
            foreach (string asmpath in assemblies_to_load)
            {
                string validp = known_plugins.Find(x => System.IO.Path.GetFileName(x).ToLower() == (asmpath + ".dll").ToLower());
                if (validp != null)
                {
                    PluginLoad(validp);
                }
                else
                {
                    DFlowCore.Log.Error("Cannot find plugin : " + asmpath);
                }
            }

            // THIS IS NECESSARY FOR ITS REAL INSTANTIATION OF CONVERTERS
            System.Diagnostics.Debug.Assert((DFlow.HandleNewConverters.Instance != null));
        }


        static string assemblyAdditionalLoadPath = null;
        static System.Reflection.Assembly LoadFromSameFolder(object sender, ResolveEventArgs args)
        {
            if (assemblyAdditionalLoadPath != null)
            {
                string assemblyPath = Path.Combine(assemblyAdditionalLoadPath, new System.Reflection.AssemblyName(args.Name).Name + ".dll");
                if (File.Exists(assemblyPath) == false) return null;
                System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom(assemblyPath);
                return assembly;
            }
            else
            {
                return null;
            }
        }




        
        
        
        
        
        public string AssemblyUpload(string asmpath, byte[] b)
        {

            // if this is a mixed mode assembly this may be better
            // it needs to be fully trusted
            // it should be in an approved plugin folder...
            bool fullyloaded = false;
            if (System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, System.IO.Path.GetFileName(asmpath)) == asmpath)
            {
                return asmpath;
            }
            if (b == null)
            {
                FileInfo fi = new FileInfo(asmpath);
                b = new byte[fi.Length];
                using (FileStream fs = new FileStream(asmpath, FileMode.Open, FileAccess.Read))
                {
                    fs.Read(b, 0, (int)fi.Length);
                }
            }

            System.Reflection.AssemblyName[] ranames;
            try
            {
                ranames = System.Reflection.Assembly.Load(b).GetReferencedAssemblies();
                fullyloaded = true;
            }
            catch
            {
                ranames = System.Reflection.Assembly.ReflectionOnlyLoad(b).GetReferencedAssemblies();
            }
            foreach (System.Reflection.AssemblyName a in ranames)
            {
                string xts = a.Name + ".dll";
                string sts = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(asmpath), xts);
                string tts = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, xts);
                if (System.IO.File.Exists(sts))
                {
                    if (!System.IO.File.Exists(tts))
                    {
                        //DFlowCore.Log.Debug("Copied : " + xts);
                        AssemblyUpload(sts, null);
                    }
                    else
                    {
                        //DFlowCore.Log.Debug("Already existing : " + xts);
                    }
                }
                else
                {
                    // TRY TO FIND IN ALTERNATE SEARCH PATH...
                    if (known_dlls.ContainsKey(sts.ToLower()))
                    {
                        sts = known_dlls[xts.ToLower()];

                        if (System.IO.File.Exists(sts))
                        {
                            if (!System.IO.File.Exists(tts))
                            {
                                //DFlowCore.Log.Debug("Copied : " + xts);
                                AssemblyUpload(sts, null);
                            }
                            else
                            {
                                //DFlowCore.Log.Debug("Already existing : " + xts);
                            }
                        }
                        else
                        {
                            //DFlowCore.Log.Debug("Not existing : " + xts);
                        }
                    }
                    else
                    {
                        //DFlowCore.Log.Debug("Not existing : " + xts);
                    }
                }
            }
            string ts = System.IO.Path.GetFileName(asmpath);
            try
            {

                if (b.Length > 0)
                {
                    if (System.IO.Path.Combine(
                        AppDomain.CurrentDomain.BaseDirectory, ts) != asmpath)
                    {
                        if (System.IO.File.Exists(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ts)))
                        {
                            using (FileStream fso = new FileStream(
                                System.IO.Path.Combine(
                                AppDomain.CurrentDomain.BaseDirectory, ts), FileMode.Truncate, FileAccess.Write))
                            {
                                fso.Write(b, 0, b.Length);
                                fso.Close();
                            }
                        }
                        else
                        {
                            using (FileStream fso = new FileStream(
                                System.IO.Path.Combine(
                                AppDomain.CurrentDomain.BaseDirectory, ts), FileMode.Create, FileAccess.Write))
                            {
                                fso.Write(b, 0, b.Length);
                                fso.Close();
                            }

                        }
                    }
                }
            }
            catch (System.Exception e)
            {
                DFlowCore.Log.Error("Error while copying assembly file " + e.ToString());
            }

            if (!fullyloaded)
            {
                try
                {
                    System.Reflection.Assembly.Load(b);
                }
                catch (System.Exception e)
                {
                    DFlowCore.Log.Debug("Assembly upload load fail" + e.ToString());
                }
            }

            return ts;
        }

        #endregion
    }

}
